#include <fstream>
#include "Dictionnary.hh"
#include "Word_i.h"
#include "Entity_i.h"
#include "Dictionnary_i.h"




using namespace std;
using namespace Dict;


static CORBA::Boolean bindObjectToName(CORBA::ORB_ptr,CORBA::Object_ptr);
static CORBA::String_var serv_msg ="Server running ... ";



int	main(int argc, char **argv)
{

	try{
		// On initialise l'ORB, puis le POA
		CORBA::ORB_var orb = CORBA::ORB_init(argc, argv,"omniORB4");
		CORBA::Object_var poaObj = orb -> resolve_initial_references("RootPOA");
    		PortableServer::POA_var rootPOA = PortableServer::POA::_narrow(poaObj);
    
    		//
    		// On obtien la reference au POA manager
    		//
    		PortableServer::POAManager_var manager = rootPOA -> the_POAManager();

		// On instancie une nouvelle implémentation de HelloWorld
		Dictionnary_i* dico = new Dictionnary_i();

		//POA_HelloWorld<HelloWorld_i> myecho(hello);

		poaObj = dico->_this();
	
		// Obtain a reference to the object, and register it in
        	// the naming service.
		//poaObj = hello._this();

		if( !bindObjectToName(orb, poaObj) )
      		return 1;



		// On obtient une référence sur cet objet
		Dictionnary_var	dicoRef = dico->_this();

		// On en récupère l'IOR sous forme de chaine
		CORBA::String_var ref = orb->object_to_string(dicoRef);

		// On crée un fichier pour y stocker l'IOR
		//ofstream	out("hello_omni.ior");

		// On écrit l'IOR
		cout << (char*) ref << endl;

		cout << "Server starting ........................... " << endl;
		
		cout << (char*)	serv_msg <<endl;	

		// On referme le fichier
		//out.close();

		// On indique au POA que l'objet hello est prêt à travailler (appel bloquant)
		manager->activate();
		orb->run();
	}
	catch(CORBA::SystemException& ex) {
    		std::cout << "Caught CORBA::" << ex._name() << endl;
  	}
  	catch(CORBA::Exception& ex) {
    		std::cout << "Caught CORBA::Exception: " << ex._name() << endl;
  	}
  	catch(omniORB::fatalException& fe) {
    		std::cout << "Caught omniORB::fatalException:" << endl;
    		std::cout << "  file: " << fe.file() << endl;
    		std::cout << "  line: " << fe.line() << endl;
    		std::cout << "  mesg: " << fe.errmsg() << endl;
  	}
	
	return 0;
	
};



static CORBA::Boolean
bindObjectToName(CORBA::ORB_ptr orb, CORBA::Object_ptr objref)
{
  CosNaming::NamingContext_var rootContext;

  try {
    // Obtain a reference to the root context of the Name service:
    CORBA::Object_var obj;
    obj = orb->resolve_initial_references("NameService");

    // Narrow the reference returned.
    rootContext = CosNaming::NamingContext::_narrow(obj);
    if( CORBA::is_nil(rootContext) ) {
      std::cout << "Failed to narrow the root naming context." << endl;
      return 0;
    }
  }
  catch (CORBA::NO_RESOURCES&) {
    std::cout << "Caught NO_RESOURCES exception. You must configure omniORB "
	 << "with the location" << endl
	 << "of the naming service." << endl;
    return 0;
  }
  catch (CORBA::ORB::InvalidName&) {
    // This should not happen!
    std::cout << "Service required is invalid [does not exist]." << endl;
    return 0;
  }

  try {
    // Bind a context called "test" to the root context:

    CosNaming::Name contextName;
    contextName.length(1);
    contextName[0].id   = (const char*) "Dictionnary";       // string copied
    contextName[0].kind = (const char*) "dictionnary_context"; // string copied
    // Note on kind: The kind field is used to indicate the type
    // of the object. This is to avoid conventions such as that used
    // by files (name.type -- e.g. test.ps = postscript etc.)

    CosNaming::NamingContext_var testContext;
    try {
      // Bind the context to root.
      testContext = rootContext->bind_new_context(contextName);
    }
    catch(CosNaming::NamingContext::AlreadyBound& ex) {
      // If the context already exists, this exception will be raised.
      // In this case, just resolve the name and assign testContext
      // to the object returned:
      CORBA::Object_var obj;
      obj = rootContext->resolve(contextName);
      testContext = CosNaming::NamingContext::_narrow(obj);
      if( CORBA::is_nil(testContext) ) {
        std::cout << "Failed to narrow naming context." << endl;
        return 0;
      }
    }

    // Bind objref with name Echo to the testContext:
    CosNaming::Name objectName;
    objectName.length(1);
    
    //seul le dictionnaire est le point d'entree    

    objectName[0].id   = (const char*) "Dictionnary";   // string copied
    objectName[0].kind = (const char*) "Object"; // string copied

    try {
      testContext->bind(objectName, objref);
    }
    catch(CosNaming::NamingContext::AlreadyBound& ex) {
      testContext->rebind(objectName, objref);
    }
    // Note: Using rebind() will overwrite any Object previously bound
    //       to /test/Echo with obj.
    //       Alternatively, bind() can be used, which will raise a
    //       CosNaming::NamingContext::AlreadyBound exception if the name
    //       supplied is already bound to an object.

    // Amendment: When using OrbixNames, it is necessary to first try bind
    // and then rebind, as rebind on it's own will throw a NotFoundexception if
    // the Name has not already been bound. [This is incorrect behaviour -
    // it should just bind].
  }
  catch(CORBA::TRANSIENT& ex) {
    std::cout << "Caught system exception TRANSIENT -- unable to contact the "
         << "naming service." << endl
	 << "Make sure the naming server is running and that omniORB is "
	 << "configured correctly." << endl;

    return 0;
  }
  catch(CORBA::SystemException& ex) {
    std::cout << "Caught a CORBA::" << ex._name()
	 << " while using the naming service." << endl;
    return 0;
  }
  return 1;
}

